﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Web.handler;
using System.Xml;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.IO;
using GatewayUtil.RequestResponse;
using System.Reflection;
using System.Web.Services.Protocols;
using System.ServiceModel;
using GatewayUtil;

namespace Web.soap
{
    /// <summary>
    /// The class provided operation like serialization and deserialization of SOAP messages
    /// </summary>
    public class SoapProcessor
    {
        private const String SOAPversion11 = "1.1";
        private const String SOAPversion12 = "1.2";
        private AssemblySerializationBinder assemblyBinder = new AssemblySerializationBinder(AppDomain.CurrentDomain.GetAssemblies());

        MessageVersion msgVersion = null;
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="msgVersion">MessageVersion of SOAP and WS-Addressing used for serialization and deserialization</param>
        /// <example>new SoapProcessor(MessageVersion.Soap11WSAddressing10);</example>
        public SoapProcessor(MessageVersion msgVersion)
        {
            this.msgVersion = msgVersion;
        }

        /// <summary>
        /// Serialize response object to the SoapMessage
        /// </summary>
        /// <param name="resp"></param>
        /// <param name="soapAction"></param>
        /// <returns>Stream that contains SoapMessage</returns>
        public MemoryStream serialize(IResponse resp, String soapAction)
        {
            MemoryStream outputStream = new MemoryStream();
            // prepare soap message
            Message msg = Message.CreateMessage(this.msgVersion, soapAction,
                resp.getResponse(), new DataContractSerializer(resp.getResponse().GetType()));

            // prepare xml writer for serialization
            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(outputStream);

            // serialize object to XML
            msg.WriteMessage(writer);

            writer.Flush();            

            return outputStream;
        }


        /// <summary>
        /// Deserialize Soap Message to the object
        /// </summary>
        /// <param name="httpStream"></param>
        /// <param name="soapAction"></param>
        /// <param name="operationTypeName">Name of class that represents object in the SoapMessage</param>
        /// <returns>it returns instance of class defined by operationTypeName param</returns>
        public object deserializeSoapMessage(Stream httpStream, string assemblyName, string operationTypeName)
        {

            Type operationType = assemblyBinder.BindToType(assemblyName, operationTypeName);

            Object request = null;
            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(httpStream, XmlDictionaryReaderQuotas.Max))
            {
                using (Message msg = Message.CreateMessage(reader, 1024, msgVersion))
                {
                    // deserialize object from XML                    
                    request = msg.GetBody<Object>(new DataContractSerializer(operationType));
                }
            }
            return request;

        }

        public string getSoapAction(HttpRequest request)
        {
            string soapAction ="null";
            if(getSoapVersion().Equals(SOAPversion12)){
                // action value looks like this:
                //Content-Type: application/soap+xml;charset=UTF-8;action="Agents.Sum"
                String[] contentValues = request.Headers.Get("Content-Type").Split(';');
                foreach (string val in contentValues)
                {
                    if(val.StartsWith("action"))
                    {                        
                        soapAction = val.Split('=')[1].Replace("\"","");
                    }
                }

            }else {
                soapAction = request.Headers.Get("SOAPAction").Replace("\"", "");
            }
            return soapAction;
        }


        private String getSoapVersion()
        {
            
            String customSetting = ConfigurationSettings.AppSettings["soapProtocolVersion"];
            //System.Configuration.Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);

                //System.Configuration.KeyValueConfigurationElement customSetting =
                  //  rootWebConfig.AppSettings.Settings["soapProtocolVersion"];
                if (null != customSetting && customSetting.Equals(SOAPversion11))
                {
                    return SOAPversion11;
                }
                else return SOAPversion12;
        }

        public MemoryStream processSoapFault(Exception exception, String soapAction)
        {
            MemoryStream outputStream = new MemoryStream();
            String action = null;
            if (soapAction == null)
            {
                action = soapAction;
            }else action = "unknown";

            FaultCode code = null;
            /*if (exception is SoapException)
            {
                code = ((SoapException)exception).Code.
            }
            else*/ code = new FaultCode("soap:Server");
            
            FaultReason reason = new FaultReason(exception.Message);
            MessageFault messageFault = MessageFault.CreateFault(code, reason);
            Message faultMsg = Message.CreateMessage(this.msgVersion, messageFault, soapAction);

            // prepare xml writer for serialization
            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(outputStream);

            // serialize object to XML
            faultMsg.WriteMessage(writer);

            writer.Flush();

            return outputStream;
        }
    }




}
